package online.shuita.gitee.mojo;

import com.google.common.collect.Lists;
import online.shuita.gitee.mojo.generator.GeneratorManager;
import online.shuita.gitee.mojo.generator.IGenerator;
import online.shuita.gitee.mojo.model.AnalyResult;
import online.shuita.gitee.mojo.service.IntfService;
import online.shuita.gitee.mojo.utils.PackageUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

// mojo注解就是maven插件的注解，具体什么我忘记了。name就是后面使用该插件的时候excuation里面的，
// 后面配置的是生命周期，我这里配置了install，即默认是安装时候执行本插件（这个可以在pom文件指定）
@Mojo(name = "generate", requiresDependencyResolution = ResolutionScope.COMPILE, defaultPhase = LifecyclePhase.COMPILE)
public class generatorMojo extends AbstractMojo {
    @Parameter(property = "targetClass")
    private String targetClass;
    @Parameter(property = "targetPackage")
    private String targetPackage;
    @Parameter(property = "bizDomain")
    private String bizDomain;
    @Parameter(property = "bizDomainMap")
    private Map<String, String> bizDomainMap;
    @Parameter(property = "generator", defaultValue = "online.shuita.gitee.mojo.generator.MarkdownGenerator")
    private String generator;
    @Parameter(property = "generatorExtParams")
    private Map<String, String> generatorExtParams;
    //项目构建根目录
    @Parameter(property = "project.build.directory", required = true)
    private File outputDirectory;

    //项目构建资源文件根目录
    @Parameter(property = "project.build.sourceDirectory", required = true, readonly = true)
    private File sourcedir;

    //项目根目录 如：E:\Research\maven_plugin
    @Parameter(property = "project.basedir", required = true, readonly = true)
    private File basedir;

    @Parameter(property = "project.compileClasspathElements", required = true, readonly = true)
    private List<String> compileClasspathElements;

    // 类加载器
    private URLClassLoader loader;

    @Parameter(defaultValue = "${project}")
    public MavenProject project;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info(targetClass);
        getLog().info(targetPackage);
        getLog().info(outputDirectory.getPath());
        getLog().info(sourcedir.getPath());
        getLog().info(basedir.getPath());
        getLog().info(String.join(",", compileClasspathElements));

        if (StringUtils.isNotBlank(targetClass) || StringUtils.isNotBlank(targetPackage)) {
            try {
                Class.forName("online.shuita.gitee.mojo.generator.MarkdownGenerator");
                if (StringUtils.isNotBlank(generator)
                        && !"online.shuita.gitee.mojo.generator.MarkdownGenerator".equalsIgnoreCase(generator)) {
                    Class.forName(generator);
                }

                Class<IGenerator> generatorInst = GeneratorManager.getManager().getGenerator(generator);
                if (null == generatorInst) {
                    getLog().error(String.format("文档生成器[%s]找不到", generator));
                    generatorInst = GeneratorManager.getManager().getGenerator("online.shuita.gitee.mojo.generator.MarkdownGenerator");
                }

                ClassLoader loader = getClassLoader(project);
//                Class target = loader.loadClass(targetClass);
                List<Class> clsList = getTargetClassList(loader);
                getLog().info(clsList.size() + "");

                IntfService service = new IntfService();
                service.setCompileClasspathElements(compileClasspathElements);
                service.setSourceBasePath(sourcedir.getPath());

                AnalyResult model = service.doAnalyse(clsList, loader);
                //重新修饰业务域名称
                doDecorateBizDomain(model);
                getLog().info(model.toString());

                getLog().info(this.getPluginContext().toString());

                generatorInst.newInstance().generateDoc(model, generatorExtParams);
            } catch (ClassNotFoundException e) {
                getLog().error("待处理的类不存在", e);
            } catch (Throwable e) {
                getLog().error("处理异常", e);
            }
        }
    }

    private void doDecorateBizDomain(AnalyResult model) {
        model.getIntfModelList().forEach(intf -> {
            if (StringUtils.isBlank(intf.getDomain())) {
                if (null != bizDomainMap && bizDomainMap.containsKey(intf.getPkgName())) {
                    intf.setDomain(bizDomainMap.get(intf.getPkgName()));
                } else if (StringUtils.isNotBlank(bizDomain)) {
                    intf.setDomain(bizDomain);
                }
            }
        });
    }

    private List<Class> getTargetClassList(ClassLoader loader) {
        try {
            if (StringUtils.isNotBlank(targetClass)) {
                String[] clsarr = targetClass.split(";");
                List<Class> clsList = Lists.newArrayList();
                for (String cls : clsarr) {
                    clsList.add(loader.loadClass(cls));
                }
                return clsList;
            } else if (StringUtils.isNotBlank(targetPackage)) {
                getLog().info(targetPackage);
                String[] packagearr = targetPackage.split(";");
                List<String> clsNameList = PackageUtils.doScan(Arrays.asList(packagearr), false, loader);
                List<Class> clsList = Lists.newArrayList();
                for (String clsName : clsNameList) {
                    getLog().info(clsName);
                    clsList.add(loader.loadClass(clsName));
                }
                return clsList;
            }
        } catch (Throwable e) {
            getLog().error("error", e);
        }
        return Lists.newArrayList();
    }

    private ClassLoader getClassLoader(MavenProject project) {
        try {
            // 所有的类路径环境，也可以直接用 compilePath
            List classpathElements = project.getCompileClasspathElements();

            classpathElements.add(project.getBuild().getOutputDirectory());
            classpathElements.add(project.getBuild().getTestOutputDirectory());
            // 转为 URL 数组
            URL urls[] = new URL[classpathElements.size()];
            for (int i = 0; i < classpathElements.size(); ++i) {
                urls[i] = new File((String) classpathElements.get(i)).toURL();
            }
            // 自定义类加载器
            return new URLClassLoader(urls, this.getClass().getClassLoader());
        } catch (Exception e) {
            getLog().debug("Couldn't get the classloader.");
            return this.getClass().getClassLoader();
        }
    }
}
